package com.zrrd.gmall.cart.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zrrd.gmall.cart.mapper.CartInfoMapper;
import com.zrrd.gmall.cart.service.CartAsyncService;
import com.zrrd.gmall.cart.service.CartInfoService;
import com.zrrd.gmall.model.cart.CartInfo;
import com.zrrd.gmall.model.product.SkuInfo;
import com.zrrd.gmall.product.fegin.ProductFeignClient;
import com.zrrd.gmall.service.constant.RedisConst;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;


import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo> implements CartInfoService {
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    //异步对象
    @Autowired
    private CartAsyncService cartAsyncService;
    @Override
    public void addToCart(Long skuId, String userId, Integer num) {
        CartInfo cartInfo;
        //try catch 保证了Mysql有异常 就停止
        try {
            //如果缓存中没有key
            if (!redisTemplate.hasKey(this.getCartKey(userId))){
                this.loadCartCache(userId);
            }
            //查询缓存中购物车对象
           cartInfo = (CartInfo) redisTemplate.boundHashOps(this.getCartKey(userId)).get(skuId.toString());
            if (cartInfo!=null){
                cartInfo.setSkuNum(cartInfo.getSkuNum()+num);
                cartInfo.setSkuPrice(productFeignClient.getSkuPrice(skuId));
                cartInfo.setUpdateTime(new Timestamp(new Date().getTime()));
                //更新（异步）
                cartAsyncService.updateCartInfo(cartInfo);
            }else {
                //feign 获取sku基本信息
                SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);

                cartInfo = new CartInfo();
                cartInfo.setSkuId(skuId);
                cartInfo.setUserId(userId);
                cartInfo.setCartPrice(skuInfo.getPrice());
                cartInfo.setSkuPrice(skuInfo.getPrice());
                cartInfo.setSkuNum(num);
                cartInfo.setSkuName(skuInfo.getSkuName());
                cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());

                cartInfo.setCreateTime(new Timestamp(new Date().getTime()));
                cartInfo.setUpdateTime(new Timestamp(new Date().getTime()));
                //保存（异步执行）
                cartAsyncService.saveCartInfo(cartInfo);
            }
        }catch (Exception e){
            //结束方法
            return;
        }

        //根据SkuId 和UserId查询购物车

        //将购物车数据存到缓存(存入Redis中的Hash类型 对象类型),有高并发风险，所以可以采取异步更新
        redisTemplate.opsForHash().put(this.getCartKey(userId),skuId.toString(),cartInfo);
        this.setCartKeyExpire(this.getCartKey(userId));
    }



    //查询购物车
    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {
        //定义最终返回的数据 1.展示临时用户购物车数据 2 登录 查询
        List<CartInfo> cartInfoList = new ArrayList<>();
        //没登录
        if (StringUtils.isEmpty(userId)){
            //返回临时用户购物车数据
            cartInfoList = this.getCartList(userTempId);
            return cartInfoList;
        }
        if (!StringUtils.isEmpty(userId)){
            //先获取临时的数据再合并
            List<CartInfo> cartTempList = this.getCartList(userTempId);
            //如果有
            if (!CollectionUtils.isEmpty(cartTempList)){
                //合并 返回合并后的集合
                cartInfoList = this.mergeToCartList(cartTempList,userId);
                //删除临时
                this.deleteCartList(userTempId);
            }
            //userId有，Temp购物车无数据
            if (StringUtils.isEmpty(userTempId) || CollectionUtils.isEmpty(cartTempList)){
                //返回当前的就可以了
                cartInfoList = this.getCartList(userId);
            }
        }
        return cartInfoList;

    }
    //异步切换
    @Override
    public void checkCart(String userId, Integer isChecked, Long skuId) {
        cartAsyncService.checkCart(userId,isChecked,skuId);
        //获取缓存中的key
        String cartKey = this.getCartKey(userId);
        //根据缓存key获取对象
        BoundHashOperations<String,String,CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        if (boundHashOperations.hasKey(skuId.toString())){
            //根据对象的小key获取数据
            CartInfo cartInfo = boundHashOperations.get(skuId.toString());
            //给购物车对象设置状态
            cartInfo.setIsChecked(isChecked);
            //更新
            boundHashOperations.put(skuId.toString(),cartInfo);
            //设置过期
            this.setCartKeyExpire(cartKey);
        }
    }
    //删除指定物品
    @Override
    public void deleteCartInfo(String userId, Long skuId) {
        cartAsyncService.deleteCartInfo(userId,skuId);
        String cartKey = this.getCartKey(userId);
        //缓存对象获取以及删除
        BoundHashOperations boundHashOperations = redisTemplate.boundHashOps(cartKey);
        if (boundHashOperations.hasKey(skuId.toString())){
            boundHashOperations.delete(skuId.toString());
        }
    }
    //查选中的数据
    @Override
    public List<CartInfo> getCartCheckedList(String userId) {
        List<CartInfo> cartInfoList = new ArrayList<>();
        //缓存中取
        String cartKey = getCartKey(userId);
        List<CartInfo> cartCacheList = redisTemplate.opsForHash().values(cartKey);
        if (!CollectionUtils.isEmpty(cartCacheList)){
            for (CartInfo cartInfo : cartCacheList) {
                //如果选中加入List
                if (cartInfo.getIsChecked().intValue() == 1){
                    cartInfoList.add(cartInfo);
                }
            }
        }
        return cartInfoList;
    }


    //合并购物车方法
    private List<CartInfo> mergeToCartList(List<CartInfo> cartTempList,String userId){
        //获取登录用户的购物车id
        List<CartInfo> cartList = this.getCartList(userId);
        //将集合拆解成Map集合 ，根据key比较 key是skuId
        Map<Long, CartInfo> infoMap = cartList.stream().collect(Collectors.toMap(CartInfo::getSkuId, cartInfo -> cartInfo));
        //遍历临时用户的购物车集合
        for (CartInfo cartInfo : cartTempList) {
            //获取当前购物车对象中的skuId
            Long skuId = cartInfo.getSkuId();
            //判断Map中是否有指定key
            if (infoMap.containsKey(skuId)){
                //获取该信息
                CartInfo cartInfoLogin = infoMap.get(skuId);
                //更新数量和日期
                cartInfoLogin.setSkuNum(cartInfoLogin.getSkuNum()+cartInfo.getSkuNum());
                cartInfoLogin.setUpdateTime(new Timestamp(new Date().getTime()));
                //如果是临时中的选中状态，那么登录状态也设置为选中
                if (cartInfoLogin.getIsChecked().intValue()==1){
                    cartInfoLogin.setIsChecked(1);
                }
                //创建条件构造器
                QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
                wrapper.eq("user_id",userId);
                wrapper.eq("sku_id",cartInfoLogin.getSkuId());
                this.update(cartInfoLogin,wrapper);
            }else {
                //临时购物车中的东西在登录用户的购物车不存在
                cartInfo.setUserId(userId);
                
                cartInfo.setUpdateTime(new Timestamp(new Date().getTime()));
                this.save(cartInfo);
            }
        }
        //查数据库更新缓存
        List<CartInfo> cartInfoList = this.loadCartCache(userId);
        return cartInfoList;
    }
    //删除临时用户的购物车
    private void deleteCartList(String userTempId){
        //异步删除购物车
        cartAsyncService.deleteCartInfo(userTempId);

        //从Redis缓存中删除
        String cartKey = this.getCartKey(userTempId);
        if (redisTemplate.hasKey(cartKey)){
            redisTemplate.delete(cartKey);
        }
    }



    //查询购物车重载id(根据用户ID查询 可以是临时的 可以是登录的
    private List<CartInfo> getCartList(String userId){
        List<CartInfo> cartInfoList = new ArrayList<>();
        //如果传递用户Id为空
        if (StringUtils.isEmpty(userId)){
            //返回空集合
            return cartInfoList;
        }
        //获取缓存的key
        String cartKey = this.getCartKey(userId);
        //从缓存中获取集合
        cartInfoList = redisTemplate.opsForHash().values(cartKey);
        //非空判断
        if (!CollectionUtils.isEmpty(cartInfoList)){
            return cartInfoList;
        }else {
            //缓存没有 查数据库 存缓存
            cartInfoList = this.loadCartCache(userId);
            return cartInfoList;
        }
    }
    //根据用户id查购物车数据库 存入缓存的方法
    @Override
    public List<CartInfo> loadCartCache(String userId){
        QueryWrapper<CartInfo>wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userId);
        //查询
        List<CartInfo> cartInfoList = this.list(wrapper);
        //判断数据库里有没有
        if (CollectionUtils.isEmpty(cartInfoList)){
            return cartInfoList;
        }
        //有就存
        Map<String,CartInfo> map = new HashMap<>();
        //为获取最新价格而遍历
        for (CartInfo cartInfo : cartInfoList) {
            BigDecimal skuPrice = productFeignClient.getSkuPrice(cartInfo.getSkuId());
            //设置最新价格
            cartInfo.setSkuPrice(skuPrice);
            //对象存Map集合
            map.put(cartInfo.getSkuId().toString(),cartInfo);
        }
        //存入
        redisTemplate.opsForHash().putAll(this.getCartKey(userId),map);
        //过期时间
        this.setCartKeyExpire(this.getCartKey(userId));
        return cartInfoList;
    }
    //定义redis缓存key
    private String getCartKey(String userId){
        return RedisConst.USER_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX;
    }
    //设置过期时间
    private void setCartKeyExpire(String cartKey) {
        redisTemplate.expire(cartKey,RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }
}
